"use client";
import { useParams } from "next/navigation";
import { useEffect } from "react";
import { usePage, usePageBlocks } from "@/hooks/use-pages";
import { usePresence } from "@/hooks/use-presence";
import { usePageRealtime } from "@/hooks/use-realtime";
import { useEditorStore } from "@/stores/editor-store";
import { PageSpinner } from "@/components/editor/page-spinner";
/**
* Page route layout: loads the page (usePage) and its top-level blocks
* (usePageBlocks), opens the realtime channel, and tracks the active page
* in the editor store. The actual editor is rendered by the route page —
* [id]/page.tsx (plain) and [id]/[block]/page.tsx (deep link with
* focusBlockId) — so the Tiptap instance mounts exactly once per URL.
*/
export default function PageLayout({ children }: { children: React.ReactNode }) {
const params = useParams<{ id: string; block?: string }>();
const pageId = params?.id ?? "";
// Data (kept here so every child route under [id] shares one query key).
const page = usePage(pageId);
usePageBlocks(pageId || "");
useEffect(() => {
useEditorStore.getState().setActivePage(pageId || null);
}, [pageId]);
// Realtime channel for the active page (presence + block overlay).
usePageRealtime(pageId || null);
// Presence emission (TASK-0093): this tab's caret + visibility →
// `presence` frames on the page channel (see hooks/use-presence.ts).
usePresence(pageId || null);
// Deep link: /w/:ws/page/:id/:block — remember the focus target so
// PageView can scroll to and expand the block once it renders.
useEffect(() => {
if (params?.block) {
useEditorStore.getState().setFocus(params.block);
}
}, [params?.block, pageId]);
if (page.isLoading) return
{msg}